package org.apache.ibatis.binding;

import org.apache.ibatis.session.SqlSession;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Lasse Voss
 */
public class MapperProxyFactory<T> {

    /**
     * 当前MapperProxyFactory对象可以创建实现了mapperInterface 接口的代理对象
     */
    private final Class<T> mapperInterface;

    /**
     * 缓存
     *  key  是mapperInterface接口中某方法对应的Method对象
     * value 是对应的MapperMethod对象
     */
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return mapperInterface;
    }

    public Map<Method, MapperMethod> getMethodCache() {
        return methodCache;
    }

    /**
     * 产生动态代理对象
     *
     * @param mapperProxy
     * @return
     */
    @SuppressWarnings("unchecked")
    protected T newInstance(MapperProxy<T> mapperProxy) {
        // 创建实现了mapperInterface接口的代理对象
        // 通过 JDK 动态代理创建代理对象
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
    }

    /**
     * 实现了创建实现了mapperInterface 接口的代理对象的功能
     * @param sqlSession
     * @return
     */
    public T newInstance(SqlSession sqlSession) {
        /*
         * 创建MapperProxy对象，每次调用都会创建新的MapperProxy 对象
         *
         * 创建 MapperProxy 对象，MapperProxy 实现了
         * InvocationHandler 接口，代理逻辑封装在此类中
         */
        final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
    }

}
